<template>
  <div class="path-roaming">
    <div class="roaming-header">
      <span>路径漫游</span>
      <i class="el-icon-circle-close close-btn" @click="close"></i>
    </div>

    <div class="roaming-body">
      <div class="label-speed body-item">
        <span>漫游速度(m/s)</span>
        <el-input v-model="roamingForm.speed" placeholder="请输入名称"></el-input>
      </div>

      <div class="label-type body-item">
        <span>漫游类型</span>
        <div class="radio-box">
          <el-radio v-model="roamingForm.type" label="view" @input="switchRoamingType">视角漫游</el-radio>
          <el-radio v-model="roamingForm.type" label="path" @input="switchRoamingType">路线漫游</el-radio>
        </div>
      </div>

      <!-- 视角漫游 -->
      <div class="label-view-list body-item" v-if="roamingForm.type == 'view'">
        <span>视角列表</span>
        <el-table :data="viewForm" style="width: 100%">
          <el-table-column prop="name" label="节点名称" width="160">
            <template slot-scope="scope">
              <span class="beyond-txt" v-if="!scope.row.isEdit">{{scope.row.name}}</span>
              <el-input v-else v-model="scope.row.name" @blur="endEditViewList(scope.row)" ref="editInput"></el-input>
            </template>
          </el-table-column>

          <el-table-column label="操作">
            <template slot-scope="scope">
              <el-button @click="editViewList(scope.row)">编辑</el-button>
              <el-button @click="removeViewList(scope.row)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>

      <!-- 路线漫游 -->
      <div v-if="roamingForm.type == 'path'">
        <div class="label-height body-item">
          <span>漫游高度(m)</span>
          <el-input v-model="roamingForm.height" placeholder="请输入高度"></el-input>
        </div>

        <div class="label-view body-item">
          <span>视角调整</span>
          <div class="view-heading orientation-box body-item">
            <span>方位角</span>
            <el-slider v-model="roamingForm.lineView.heading" show-input :min="-180" :max="180" :step="0.1" input-size="mini"></el-slider>
          </div>

          <div class="view-pitch orientation-box body-item">
            <span>俯仰角</span>
            <el-slider v-model="roamingForm.lineView.pitch" show-input :min="-180" :max="180" x :step="0.1" input-size="mini"></el-slider>
          </div>

          <div class="view-rol orientation-box body-item">
            <span>翻滚角</span>
            <el-slider v-model="roamingForm.lineView.roll" show-input :min="-180" :max="180" :step="0.1" input-size="mini"></el-slider>
          </div>
        </div>

        <div class="label-path-list body-item">
          <span>路线坐标</span>
          <el-input type="textarea" :rows="5" resize="none" :disabled="true" placeholder="" v-model="roamingForm.postion">
          </el-input>
        </div>
      </div>

      <div class="body-submit">
        <el-button v-text="roamingForm.type == 'view' ? '添加视角' : '绘制路线'" @click="setPath"></el-button>
        <el-button @click="startRoaming">播放</el-button>
        <el-button @click="stopRoaming">停止</el-button>
      </div>
    </div>
  </div>
</template>

<script>
import * as turf from '@turf/turf';
import Mark from '@/components/layoutSubassemb/js/mark.js';
export default {
  data() {
    return {
      roamingForm: {
        speed: '200',
        type: 'view',
        height: '100',
        postion: '',
        lineView: {
          heading: -90,
          pitch: 0,
          roll: 60
        }
      },
      viewForm: [],
      editRow: null,
      statusStop: null,
    };
  },

  methods: {
    // 设置漫游
    setPath() {
      const { type } = this.roamingForm;
      if (type == 'view') {
        this.addCameraView();
      } else {
        this.drawPath();
      }
    },

    // 开始漫游
    startRoaming() {
      this.switchRoamingType();

      const { type } = this.roamingForm;
      if (type == 'view') {
        this.cameraViewRoaming();
      } else {
        this.pathRoaming();
      }
    },

    // 停止漫游
    stopRoaming() {
      this.switchRoamingType();

      const { type } = this.roamingForm;
      if (type == 'view') {
        this.stopCameraViewRoaming();
      } else {
        this.stopPathRoaming();
      }
    },

    switchRoamingType() {
      this.stopCameraViewRoaming();
      this.stopPathRoaming();
      this._Mark.removeMark();
      this._Mark.m_end();
    },

    /**
     * 视角漫游
     * */
    addCameraView() {
      const node = {
        id: this.$guid(),
        name: `节点${this.viewForm.length + 1}`,
        isEdit: false,
        camerastate: {
          position: this.viewer.camera.positionWC.clone(),
          direction: this.viewer.camera.directionWC.clone(),
          up: this.viewer.camera.upWC.clone(),
        }
      };
      this.viewForm.push(node);
    },

    cameraViewRoaming() {
      const speed = Number(this.roamingForm.speed.replace(/\s*/g, ""));
      if (!speed) return this.message('漫游速度必须为数字类型值');
      const viewForm = this.viewForm;
      if (viewForm.length <= 1) return this.message('需要两个或以上视角才能进行漫游操作');

      let flyInfo = [];
      viewForm.forEach((item, index) => {
        // 计算距离
        if (index + 1 == viewForm.length) return;
        let pos = this.cartesian2wgs84(item.camerastate.position);
        let posEnd = this.cartesian2wgs84(viewForm[index + 1].camerastate.position);
        const _distance =
          turf.distance(
            turf.point([pos[0], pos[1]]),
            turf.point([posEnd[0], posEnd[1]]),
            { units: 'kilometers' }
          ) * 1000;
        if (index == 0) {
          flyInfo.push(
            Object.assign({}, Object.create(Object.getPrototypeOf(item)), item)
          );
        }
        flyInfo.push({
          distance: _distance,
          ...Object.assign(
            {},
            Object.create(Object.getPrototypeOf(viewForm[index + 1])),
            viewForm[index + 1]
          ),
        });
      });
      if (flyInfo.length < 2) return this.message('需要两个或以上视角才能进行漫游操作');

      flyInfo.forEach((el) => {
        // 计算飞行时间
        if (!el.distance) return;
        el.time = el.distance / speed;
      });
      this.doFly(flyInfo);
    },

    stopCameraViewRoaming() {
      this.viewer.camera.flyTo({
        destination: this.viewer.camera.positionWC.clone(),
        duration: 0.5,
        easingFunction: Cesium.EasingFunction.LINEAR_NONE,
        orientation: {
          direction: this.viewer.camera.directionWC.clone(),
          up: this.viewer.camera.upWC.clone(),
        }
      });
    },

    // 视角列表漫游递归函数
    doFly(flyInfo) {
      let curFlyInfo = flyInfo.find((el) => el.isFly == undefined);
      if (!curFlyInfo) return;

      if (!curFlyInfo.time) {
        this.viewer.scene.camera.setView({
          destination: curFlyInfo.camerastate.position,
          orientation: curFlyInfo.camerastate,
        });
        flyInfo.find((el) => el.isFly === undefined).isFly = true;
        this.doFly(flyInfo);
      } else {
        this.viewer.camera.flyTo({
          destination: curFlyInfo.camerastate.position,
          duration: curFlyInfo.time,
          maximumHeight: this.cartesian2wgs84(
            curFlyInfo.camerastate.position
          )[2],
          easingFunction: Cesium.EasingFunction.LINEAR_NONE,
          orientation: {
            direction: curFlyInfo.camerastate.direction,
            up: curFlyInfo.camerastate.up,
          },
          complete: () => {
            flyInfo.find((el) => el.isFly === undefined).isFly = true;
            this.doFly(flyInfo);
          },
        });
      }
    },

    // 笛卡尔坐标转84经纬度
    cartesian2wgs84(coor) {
      var ellipsoid = this.viewer.scene.globe.ellipsoid;
      var cartesian3 = coor;
      var cartograhphic = ellipsoid.cartesianToCartographic(cartesian3);
      var lng = Cesium.Math.toDegrees(cartograhphic.longitude);
      var lat = Cesium.Math.toDegrees(cartograhphic.latitude);
      var alt = cartograhphic.height;
      return [lng, lat, alt];
    },

    // 编辑视角列表
    editViewList(row) {
      row.isEdit = true;
      this.$nextTick(() => {
        this.$refs.editInput.focus();
      });
    },

    endEditViewList(row) {
      this.viewForm.forEach(item => {
        if (item.id != row.id && item.name == row.name) {
          const nameList = this.viewForm.map(e => { return e.name; });
          row.name = this.unitListName(nameList, row.name);
        }
      });
      row.isEdit = false;
    },

    unitListName(list, n) {
      function check(name) {
        let n = name.match(/[^\.]*/)[0];
        return function (a) {
          return a.indexOf(n) == 0;
        };
      }
      list = list.filter(check(n));
      let on = n.match(/([^\.]*)(.*)/);

      // 重名文件最多10000个
      for (let i = 1; i < 10000; i++) {
        let nn = on[1] + '_' + String(i);
        if (!list.find((element) => (element == nn + on[2])))
          return nn + on[2];
      }
    },

    // 删除视角列表
    removeViewList(row) {
      for (let i = 0; i < this.viewForm.length; i++) {
        const item = this.viewForm[i];
        if (item.id == row.id) {
          this.viewForm.splice(i, 1);
          i--;
        }
      }
    },

    /**
     * 路线漫游
     * */
    drawPath() {
      this._Mark.removeMark();
      this._Mark.loadLine({
        show: true,
        callback: (positions) => {
          if (positions && positions.length) {
            this.roamingForm.postion = JSON.stringify(positions);
          }
        }
      });
    },

    pathRoaming() {
      this._Mark.removeMark();
      const speed = Number(this.roamingForm.speed.replace(/\s*/g, ""));
      if (!speed) return this.message('漫游速度必须为数字类型值');
      const height = Number(this.roamingForm.height.replace(/\s*/g, ""));
      if (!height) return this.message('高度必须为数字类型值');
      const postion = this.roamingForm.postion && JSON.parse(this.roamingForm.postion);
      if (postion.length <= 1) return this.message('请绘制漫游路线');

      let positions = postion.map((el, index) => {
        let pos_84 = this.transformCartesianToWGS84(
          new Cesium.Cartesian3(el.x, el.y, el.z)
        );
        let resultPos = new Cesium.Cartesian3.fromDegrees(
          pos_84.lng,
          pos_84.lat,
          this.roamingForm.height
        );
        return resultPos;
      });

      let allDis = this.getSpaceDistance(positions);
      let start = Cesium.JulianDate.fromDate(new Date(2022, 6, 12, 15));
      let totalSeconds = allDis / speed;
      var stop = Cesium.JulianDate.addSeconds(
        start,
        totalSeconds,
        new Cesium.JulianDate()
      );
      var position = new Cesium.SampledPositionProperty();

      this.viewer.clock.startTime = start.clone();
      this.viewer.clock.stopTime = stop.clone();
      this.viewer.clock.currentTime = start.clone();
      this.viewer.clock.clockRange = Cesium.ClockRange.CLAMPED;
      let curTime = null;
      positions.forEach((pos, index) => {
        if (index == 0) {
          position.addSample(start, pos);
          curTime = start.clone();
        } else {
          let timeStep =
            (this.getSpaceDistance([pos, positions[index - 1]]) / allDis) *
            totalSeconds;
          curTime = Cesium.JulianDate.addSeconds(
            curTime,
            timeStep,
            new Cesium.JulianDate()
          );
          position.addSample(curTime, pos);
        }
      });
      this.lastFlyTime = curTime;
      this.flyEntity = this.viewer.entities.add({
        id: 'carModel',
        position: position,
        orientation: new Cesium.VelocityOrientationProperty(position),
        model: {
          uri: 'data/model/car.glb',
          maximumScale: 1,
          runAnimations: false,
          show: false
        },
      });

      setTimeout(() => {
        this.viewer.clock.shouldAnimate = true;
        this.viewer.clock.onTick.addEventListener(this.trackModel);
      }, 1000);
    },

    transformCartesianToWGS84(cartesian) {
      if (this.viewer && cartesian) {
        var ellipsoid = Cesium.Ellipsoid.WGS84;
        var cartographic = ellipsoid.cartesianToCartographic(cartesian);
        return {
          lng: Cesium.Math.toDegrees(cartographic.longitude),
          lat: Cesium.Math.toDegrees(cartographic.latitude),
          alt: cartographic.height
        };
      }
    },

    // 计算笛卡尔坐标数组空间距离
    getSpaceDistance(positions) {
      var distance = 0;
      for (var i = 0; i < positions.length - 1; i++) {
        var point1cartographic = Cesium.Cartographic.fromCartesian(
          positions[i]
        );
        var point2cartographic = Cesium.Cartographic.fromCartesian(
          positions[i + 1]
        );
        /**根据经纬度计算出距离**/
        var geodesic = new Cesium.EllipsoidGeodesic();
        geodesic.setEndPoints(point1cartographic, point2cartographic);
        var s = geodesic.surfaceDistance;
        //返回两点之间的距离
        s = Math.sqrt(
          Math.pow(s, 2) +
          Math.pow(point2cartographic.height - point1cartographic.height, 2)
        );
        distance = distance + s;
      }
      return distance.toFixed(2);
    },

    trackModel() {
      let center = this.flyEntity.position.getValue(
        this.viewer.clock.currentTime
      );
      if (!center || !center.x) {
        this.stopPathRoaming();
        return;
      }
      let orientation = this.flyEntity.orientation.getValue(
        this.viewer.clock.currentTime
      );
      let transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
      transform = Cesium.Matrix4.fromRotationTranslation(
        Cesium.Matrix3.fromQuaternion(orientation),
        center
      );

      const { lineView } = this.roamingForm;
      const { heading, pitch, roll } = lineView;
      this.viewer.camera.lookAtTransform(
        transform,
        new Cesium.Cartesian3(heading, pitch, roll)
      );
      if (
        Cesium.JulianDate.compare(
          this.viewer.clock.currentTime,
          this.lastFlyTime
        ).toFixed(2) >= 0
      ) {
        this.stopPathRoaming();
      }
    },

    stopPathRoaming() {
      this.viewer.clock.shouldAnimate = false;
      this.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY); // 取消视角锁定
      if (this.flyEntity) {
        this.viewer.entities.remove(this.flyEntity);
        delete this.flyEntity;
      }
      this.viewer.clock.onTick.removeEventListener(this.trackModel);
    },

    close() {
      this.$emit('close');
    },

    // 提示
    message(message = '警告', type = 'warning') {
      this.$message({
        message: message,
        type: type
      });
    }
  },

  created() {
    this.viewer = this.Global.viewer;
    this._Mark = new Mark({ Vm: this, viewer: this.viewer });
    this.flyEntity = null;
    this.lastFlyTime = null;
  },

  beforeDestroy() {
    this.switchRoamingType();
    this._Mark.destroy();
  }
}
</script>

<style lang="less" scoped>
.path-roaming {
  position: fixed;
  right: 10px;
  top: 94px;
  width: 265px;
  padding: 15px 0;
  box-sizing: border-box;
  border-radius: 3px;
  background-color: #444444;
  z-index: 999;
  .roaming-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 10px 15px 10px;
    box-sizing: border-box;
    border-bottom: 1px solid #565656;
    font-size: 14px;
    color: #b4b4b4;
    .close-btn {
      cursor: pointer;
    }
  }

  .roaming-body {
    .body-item {
      display: flex;
      flex-direction: column;
      justify-content: space-around;
      padding: 15px 10px 0 10px;
      box-sizing: border-box;
      font-size: 14px;
      color: #b4b4b4;
      & > span {
        margin-bottom: 10px;
      }

      .describe-num-words {
        display: flex;
        justify-content: flex-end;
        width: 100%;
        margin-bottom: 0;
        margin-top: 10px;
      }
    }

    .radio-box {
      padding: 5px 0;
      box-sizing: border-box;
      /deep/.el-radio {
        .el-radio__label {
          font-size: 13px;
          color: #b4b4b4;
        }
      }
    }

    .label-name,
    .label-speed,
    .label-height {
      /deep/.el-input__inner {
        background: rgba(0, 0, 0, 0);
        border: none;
        border-bottom: 1px solid #565656;
        border-radius: 0;
        padding: 0;
        font-size: 14px;
        color: #fff;
      }
    }

    .label-view {
      .orientation-box {
        font-size: 13px;
        /deep/.el-input-number {
          width: 100px;
          height: 30px;
          .el-input-number__decrease,
          .el-input-number__increase,
          .el-input__inner {
            background-color: rgba(0, 0, 0, 0);
          }

          .el-input-number__decrease,
          .el-input-number__increase {
            width: 18px;
            color: #fff;
            &:hover {
              color: #6fa7e8;
            }
          }

          .el-input__inner {
            padding: 0 10px;
            border: 1px solid #e6e6e6;
            font-size: 14px;
            color: #fff;
            &:hover {
              border: 1px solid #e6e6e6;
            }
          }
        }

        /deep/.el-slider {
          padding-left: 10px;
          box-sizing: border-box;
          .el-slider__runway {
            width: 45%;
          }
        }
      }
    }

    .label-view-list {
      /deep/.el-table {
        background: rgba(0, 0, 0, 0);
        &::before {
          background-color: #565656;
        }

        .el-table__header-wrapper {
          .el-table__header {
            .has-gutter {
              tr {
                background: rgba(0, 0, 0, 0);
                th {
                  padding: 0;
                  background: rgba(0, 0, 0, 0);
                  .cell {
                    padding: 0;
                    font-size: 12px;
                  }
                }

                .is-leaf {
                  border-bottom: 1px solid #565656;
                }
              }
            }
          }
        }

        .el-table__body-wrapper {
          height: 200px;
          overflow-y: auto;
          .el-table__body {
            .el-table__row {
              background: rgba(0, 0, 0, 0);
              &:hover > td.el-table__cell {
                background-color: #535353;
              }

              .el-table__cell {
                padding: 0;
                border-bottom: 1px solid #565656;
                color: #ffffff;
                .cell {
                  display: flex;
                  align-items: center;
                  padding: 5px 10px 5px 0;
                  box-sizing: border-box;
                  span {
                    display: inline-block;
                    width: 100%;
                  }

                  .el-input__inner {
                    width: 150px;
                    height: 23px;
                    background: rgba(0, 0, 0, 0);
                    font-size: 12px;
                    color: #ffffff;
                  }
                }

                .el-button {
                  border: none;
                  padding: 4px;
                  color: #fff;
                  &:first-child {
                    background-color: #696969;
                    &:hover {
                      background-color: #535353;
                    }
                  }

                  &:last-child {
                    background-color: #535353;
                    &:hover {
                      background-color: #696969;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }

    .label-path-list {
      /deep/.el-textarea__inner {
        background: #3d3d3d;
        border: 1px solid #565656;
        font-size: 14px;
        color: #b4b4b4;
      }
    }

    .body-submit {
      display: flex;
      justify-content: space-between;
      flex-wrap: wrap;
      column-gap: 10px;
      padding: 15px 10px 0;
      box-sizing: border-box;
      /deep/.el-button {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 106px;
        height: 24px;
        padding: 0 10px;
        margin: 10px 0 0 0;
        border: none;
        background-color: #535353;
        color: #ffffff;
        &:hover {
          background-color: #696969;
        }
      }
    }
  }
}

.beyond-txt {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  -o-text-overflow: ellipsis;
}
</style>